home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3.2
/
Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO
/
packet
/
n17jsrc
/
nr4user.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-11
|
5KB
|
224 lines
/* net/rom level 4 (transport) protocol user level calls
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
* non-commercial distribution only.
*/
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "ax25.h"
#include "lapb.h"
#include "netrom.h"
#include "nr4.h"
#include <ctype.h>
#undef NR4DEBUG
/* Open a NET/ROM transport connection */
struct nr4cb *
open_nr4(local,remote,mode,r_upcall,t_upcall,s_upcall,user)
struct nr4_addr *local ; /* local node address */
struct nr4_addr *remote ; /* destination node address */
int mode ; /* active/passive/server */
void (*r_upcall)() ; /* received data upcall */
void (*t_upcall)() ; /* transmit upcall */
void (*s_upcall)() ; /* state change upcall */
int user ; /* user linkage area */
{
struct nr4cb *cb ;
struct nr4hdr hdr ;
struct nr4_addr nr4tmp;
if ((cb = new_n4circ()) == NULLNR4CB)
return NULLNR4CB ; /* No circuits available */
if(remote == NULLNRADDR){
remote = &nr4tmp;
setcall(remote->user," ");
setcall(remote->node," ");
}
/* Stuff what info we can into control block */
ASSIGN(cb->remote,*remote) ;
/* Save local address for connect retries */
ASSIGN(cb->local,*local) ;
cb->r_upcall = r_upcall ;
cb->t_upcall = t_upcall ;
cb->s_upcall = s_upcall ;
cb->user = user ;
cb->clone = 0 ;
switch(mode){
case AX_SERVER:
cb->clone = 1;
case AX_PASSIVE: /* Note fall-thru */
cb->state = NR4STLISTEN;
return cb;
case AX_ACTIVE:
break;
}
/* Format connect request header */
hdr.opcode = NR4OPCONRQ ;
hdr.u.conreq.myindex = cb->mynum ;
hdr.u.conreq.myid = cb->myid ;
hdr.u.conreq.window = Nr4window ;
memcpy(hdr.u.conreq.user,local->user,AXALEN);
/* If I have a unique callsign per interface, then a layer violation */
/* will be required to determine the "real" callsign for my */
/* (virtual) node. This suggests that callsign-per-interface is not */
/* desirable, which answers *that* particular open question. */
memcpy(hdr.u.conreq.node,local->node,AXALEN);
/* Set and start connection retry timer */
cb->cdtries = 1 ;
cb->srtt = Nr4irtt ;
set_timer(&cb->tcd,2 * cb->srtt);
cb->tcd.func = nr4cdtimeout ;
cb->tcd.arg = cb ;
start_timer(&cb->tcd) ;
/* Send connect request packet */
nr4sframe(remote->node,&hdr,NULLBUF) ;
/* Set up initial state and signal state change */
cb->state = NR4STDISC ;
nr4state(cb, NR4STCPEND) ;
/* Return control block address */
return cb ;
}
/* Send a net/rom transport data packet */
int
send_nr4(cb,bp)
struct nr4cb *cb ;
struct mbuf *bp ;
{
if (cb == NULLNR4CB || bp == NULLBUF)
return -1 ;
enqueue(&cb->txq,bp) ;
return nr4output(cb) ;
}
/* Receive incoming net/rom transport data */
struct mbuf *
recv_nr4(cb,cnt)
struct nr4cb *cb ;
int16 cnt ;
{
struct mbuf *bp ;
if (cb->rxq == NULLBUF)
return NULLBUF ;
if (cnt == 0) {
bp = cb->rxq ; /* Just give `em everything */
cb->rxq = NULLBUF ;
}
else {
bp = ambufw(cnt);
bp->cnt = pullup(&cb->rxq,bp->data,cnt);
}
/* If this has un-choked us, reopen the window */
if (cb->qfull && len_p(cb->rxq) < Nr4qlimit) {
cb->qfull = 0 ; /* Choke flag off */
nr4ackit(cb) ; /* Get things rolling again */
}
return bp ;
}
/* Close a NET/ROM connection */
void
disc_nr4(cb)
struct nr4cb *cb ;
{
struct nr4hdr hdr ;
if (cb->state == NR4STLISTEN) {
free_n4circ(cb);
return;
}
if (cb->state != NR4STCON)
return ;
/* Format disconnect request packet */
hdr.opcode = NR4OPDISRQ ;
hdr.yourindex = cb->yournum ;
hdr.yourid = cb->yourid ;
/* Set and start timer */
cb->cdtries = 1 ;
set_timer(&cb->tcd,2 * cb->srtt);
cb->tcd.func = nr4cdtimeout ;
cb->tcd.arg = cb ;
start_timer(&cb->tcd) ;
/* Send packet */
nr4sframe(cb->remote.node, &hdr, NULLBUF) ;
/* Signal state change. nr4state will take care of stopping */
/* the appropriate timers and resetting window pointers. */
nr4state(cb, NR4STDPEND) ;
}
/* Abruptly terminate a NET/ROM transport connection */
void
reset_nr4(cb)
struct nr4cb *cb ;
{
cb->dreason = NR4RRESET ;
nr4state(cb,NR4STDISC) ;
}
/* Force retransmission on a NET/ROM transport connection */
int
kick_nr4(cb)
struct nr4cb *cb ;
{
unsigned seq ;
struct timer *t ;
if(!nr4valcb(cb))
return -1 ;
switch (cb->state) {
case NR4STCPEND:
case NR4STDPEND:
stop_timer(&cb->tcd) ;
nr4cdtimeout(cb) ;
break ;
case NR4STCON:
if (cb->nextosend != cb->ackxpected) { /* if send window is open: */
for (seq = cb->ackxpected ;
nr4between(cb->ackxpected, seq, cb->nextosend) ;
seq = (seq + 1) & NR4SEQMASK) {
t = &cb->txbufs[seq % cb->window].tretry ;
stop_timer(t) ;
t->state = TIMER_EXPIRE ; /* fool retry routine */
}
nr4txtimeout(cb) ;
}
break ;
}
return 0 ;
}